﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xrm.Sdk;

using System.Fakes;
using Microsoft.Xrm.Sdk.Fakes;
using Xrm.Framework.Test.Unit;

namespace Xrm.Framework.Test.Unit.Fakes
{
    /// <summary>
    /// Base Class for all Dynamics CRM Plugin Unit Tests using Fakes
    /// </summary>
    public abstract class PluginUnitTest : Xrm.Framework.Test.Unit.PluginUnitTest
    {
        #region Instance Variables

        private Guid _stubBusinessUnitId = Guid.NewGuid();
        private Guid _stubContextUserId = Guid.NewGuid();
        private Guid _stubCorrelationId = Guid.NewGuid();
        private Guid _stubInitiatingUserId = Guid.NewGuid();
        private DateTime _stubOperationCreatedOn = DateTime.Now;
        private Guid _stubOperationId = Guid.NewGuid();
        private Guid _stubOrganizationId = Guid.NewGuid();
        private Guid _stubPrimaryEntityId = Guid.NewGuid();
        private Guid _stubRequestId = Guid.NewGuid();
        private ParameterCollection inputParameters = new ParameterCollection();
        private ParameterCollection outputParameters = new ParameterCollection();

        #endregion

        #region Properties

        protected StubITracingService TracingServiceStub
        {
            get;
            set;
        }

        protected StubIOrganizationServiceFactory OrganizationServiceFactoryStub
        {
            get;
            set;
        }

        /// <summary>
        /// Organisation Service using system account
        /// </summary>
        protected StubIOrganizationService SystemOrganizationServiceStub
        {
            get;
            set;
        }

        protected StubIOrganizationService OrganizationServiceStub
        {
            get;
            set;
        }

        protected StubIServiceProvider ServiceProviderStub
        {
            get;
            set;
        }

        protected StubIPluginExecutionContext PluginExecutionContextStub
        {
            get;
            set;
        }

        #endregion

        #region Constructors

        public PluginUnitTest()
            : base()
        {
            Init();
        }

        #endregion

        #region Setup Stubs

        protected void Init()
        {
            this.PluginExecutionContextStub = new StubIPluginExecutionContext();
            this.TracingServiceStub = new StubITracingService();
            this.OrganizationServiceFactoryStub = new StubIOrganizationServiceFactory();
            this.SystemOrganizationServiceStub = new StubIOrganizationService();
            this.OrganizationServiceStub = new StubIOrganizationService();
            
            InitPluginExecutionContextMock(PluginExecutionContextStub);

            OrganizationServiceStub.CreateEntity = (entity) =>
            {
                return Guid.NewGuid();
            };

            SystemOrganizationServiceStub.CreateEntity = (entity) =>
            {
                return Guid.NewGuid();
            };

            OrganizationServiceFactoryStub.CreateOrganizationServiceNullableOfGuid = (id) =>
            {
                if (id == this.PluginExecutionContextStub.UserIdGet())
                {
                    return this.OrganizationServiceStub;
                }
                else if (id == null)
                    return this.SystemOrganizationServiceStub;
                else
                    return new StubIOrganizationService();
            };

            ServiceProviderStub.GetServiceType = (type) =>
            {
                if (type == typeof(ITracingService))
                    return this.TracingServiceStub;
                else if (type == typeof(IOrganizationServiceFactory))
                    return this.OrganizationServiceFactoryStub;
                else if (type == typeof(IPluginExecutionContext))
                    return this.PluginExecutionContextStub;
                else
                    return null;
            };

        }

        protected void InitPluginExecutionContextMock(StubIPluginExecutionContext stubIPluginExecutionContext)
        {
            stubIPluginExecutionContext.BusinessUnitIdGet = () => { return _stubBusinessUnitId; };
            stubIPluginExecutionContext.CorrelationIdGet = () => { return _stubCorrelationId; };
            stubIPluginExecutionContext.DepthGet = () => { return 0; };
            stubIPluginExecutionContext.InitiatingUserIdGet = () => { return _stubInitiatingUserId; };
            stubIPluginExecutionContext.InputParametersGet = () => 
            { 
                if(this.inputParameters == null)
                    this.inputParameters = new ParameterCollection();

                return this.inputParameters; 
            };
            stubIPluginExecutionContext.OutputParametersGet = () => 
            {
                if (this.outputParameters == null)
                    this.outputParameters = new ParameterCollection();

                return this.outputParameters; 
            };
            stubIPluginExecutionContext.IsExecutingOfflineGet = () => { return false; };
            stubIPluginExecutionContext.IsInTransactionGet = () => { return false; };
            stubIPluginExecutionContext.IsOfflinePlaybackGet = () => { return false; };
            stubIPluginExecutionContext.IsolationModeGet = () => { return (int)PluginAssembyIsolationMode.Sandbox; };
            stubIPluginExecutionContext.MessageNameGet = () => { return string.Empty; };
            stubIPluginExecutionContext.ModeGet = () => { return (int)PluginMode.Synchronous; };
            stubIPluginExecutionContext.OperationCreatedOnGet = () => { return _stubOperationCreatedOn; };
            stubIPluginExecutionContext.OperationIdGet = () => { return _stubOperationId; };
            stubIPluginExecutionContext.OrganizationIdGet = () => { return _stubOrganizationId; };
            stubIPluginExecutionContext.OrganizationNameGet = () => { return string.Empty; };    
            stubIPluginExecutionContext.OwningExtensionGet = () => { return new EntityReference(); };
            stubIPluginExecutionContext.PostEntityImagesGet = () => { return new EntityImageCollection(); };
            stubIPluginExecutionContext.PreEntityImagesGet = () => { return new EntityImageCollection(); };
            stubIPluginExecutionContext.PrimaryEntityIdGet = () => { return Guid.NewGuid(); };
            stubIPluginExecutionContext.PrimaryEntityNameGet = () => { return string.Empty; };
            stubIPluginExecutionContext.RequestIdGet = () => { return _stubRequestId; };
            stubIPluginExecutionContext.SecondaryEntityNameGet = () => { return string.Empty; };
            stubIPluginExecutionContext.SharedVariablesGet = () => { return new ParameterCollection(); };
            stubIPluginExecutionContext.UserIdGet = () => { return _stubContextUserId; };
            stubIPluginExecutionContext.StageGet = () => { return (int)SdkMessageProcessingStepImage.PreValidation; };
        }

        protected override IServiceProvider CreateServiceProvider()
        {
            if (this.ServiceProviderStub == null)
                this.ServiceProviderStub = new StubIServiceProvider();
            return this.ServiceProviderStub;
        }

        #endregion

        #region Helper Methods

        protected override void SetPluginEvent(string primaryEntityName, string messageName, SdkMessageProcessingStepImage stage)
        {
            this.PluginExecutionContextStub.PrimaryEntityNameGet = () => { return primaryEntityName; };
            this.PluginExecutionContextStub.MessageNameGet = () => { return messageName; };
            this.PluginExecutionContextStub.StageGet = () => { return (int)stage; };
        }

        #endregion
    }
}
